package main.loading;

import java.util.concurrent.Callable;

import settings.GraphicSettings;

import com.jme.util.GameTaskQueueManager;

import logic.nodes.lod.blocks.LeafBlock;
import logic.ships.hunter.CounterMeasure;
import main.InitGame;
import map.Map;

import factories.EffectFactory;
import gameStates.gui.GraphicChangeLoadingState;

public class GraphicChangeProcess extends LoadingProcess {
	
	private static final int VIEW_DIST_P = 5;
	private static final int LEAFS_P = 95;
	private static final int LEAFS_AMOUNT = LEAFS_P - VIEW_DIST_P;
	private static final int STATIC_P = 100;
	
	private boolean updateGeometry, updateTexture, updateFilters, updateEffects;
	
	public GraphicChangeProcess(GraphicChangeLoadingState loadingState) {
		super(loadingState);
	}
	
	@Override
	protected void initLoadingSteps() {
		GraphicSettings newSettings = GraphicSettings.get();
		GraphicSettings oldSettings = ((GraphicChangeLoadingState)loadingState).getOldGraphicSettings();
		
		updateGeometry = !oldSettings.getGeometryQuality().equals(newSettings.getGeometryQuality()) || 
						!oldSettings.getLODString().equals(newSettings.getLODString());
		updateTexture = !oldSettings.getTextureQuality().equals(newSettings.getTextureQuality()) || 
						!oldSettings.getNormalQuality().equals(newSettings.getNormalQuality()) || 
						!oldSettings.getSpecularQuality().equals(newSettings.getSpecularQuality()) || 
						!oldSettings.getBumpQuality().equals(newSettings.getBumpQuality()) || 
						!oldSettings.getShaderQuality().equals(newSettings.getShaderQuality());
		updateFilters = !oldSettings.getTextureFilterString().equals(newSettings.getTextureFilterString()) || 
						!oldSettings.getAnisotropString().equals(newSettings.getAnisotropString());
		updateEffects = !oldSettings.getEffectsQuality().equals(newSettings.getEffectsQuality());
		
		boolean updateLeafBlocks = updateGeometry || updateTexture || updateFilters || updateEffects;
		addLoadingStep(changeViewDistance());
		//15% done
		
		int leafBlocksAmount = LeafBlock.allLeafBlocks.size();
		if(updateLeafBlocks && leafBlocksAmount > 0) {
			int blocksPerPercent = leafBlocksAmount / LEAFS_AMOUNT;
			int mod = leafBlocksAmount % LEAFS_AMOUNT;
			int percentage = VIEW_DIST_P;
			for(int i = 1; i <= leafBlocksAmount; i++) {
				LeafBlock leafBlock = LeafBlock.allLeafBlocks.get(i - 1);
				if(i == leafBlocksAmount && mod != 0) percentage = LEAFS_P;
				else if(i % blocksPerPercent == 0) percentage++;
				addLoadingStep(changeLeafBlock(leafBlock, percentage));
			}
			//95% done
			
			addLoadingStep(updateStatics());
			//100% done
		}
	}
	
	private LoadingStep changeViewDistance() {
		return new LoadingStep(VIEW_DIST_P) {
			@Override
			public boolean perform() throws Exception {
				LeafBlock.updateViewDist();
				return true;
			}
		};
	}
	
	private LoadingStep changeLeafBlock(final LeafBlock leafBlock, int percentage) {
		return new LoadingStep(percentage) {
			@Override
			public boolean perform() throws Exception {
				try {
					GameTaskQueueManager.getManager().update(new Callable<Void>() {
						@Override
						public Void call() throws Exception {
							if(updateGeometry) leafBlock.updateGeometrySettings();
							else if(updateTexture) leafBlock.updateTextureSettings();
							else if(updateFilters) leafBlock.updateTextureFilters();
							
							if(updateEffects) leafBlock.updateTrailQuality();
							return null;
						}
					}).get();
				} catch(Exception e) {
					e.printStackTrace();
				}
				return true;
			}
		};
	}
	
	private LoadingStep updateStatics() {
		return new LoadingStep(STATIC_P) {
			@Override
			public boolean perform() throws Exception {
				EffectFactory.updateGraphicSettings();
				CounterMeasure.changeGraphicSettings();
				Map currentMap = InitGame.get().getCurrentMap();
				if(currentMap != null) currentMap.getBackground().updateGraphicSettings();
				return true;
			}
		};
	}
	
	@Override
	public void abort() {}
	
	@Override
	public void finish() {
		InitGame.get().setChangingGraphics(false);
	}
	
	@Override
	public void cleanup() {
		super.cleanup();
	}
	
	@Override
	public boolean canBeAborted() { return false; }
}